import { AudioClip,NodePool ,Node} from "cc"; 
import { AudioEffect } from "./AudioEffect";
import { resLoader } from "../loader/ResLoader";
import { hiyooo } from "../../HiYOOO";
const AE_ID_MAX = 30000;
export class AudioEffectPool{

    //TypeScript get 、set方法
    /**
     * get 是一个用于获取对象属性值的访问器函数，它会在访问者获取属性时自动调用。
     * set 是一个用于设置对象属性值的访问器函数，它会在访问者设置属性值时自动调用。
     * 通过使用 get 和 set，我们可以隐藏对象属性的实现细节，同时可以对属性值进行校验和处理。
     * 这种方式使对象的属性更加安全，而且可以提供更好的封装性。
     * 所以，这里的switch属性的get和set方法就是通过TypeScript的语法实现的。 
     * audioMusic 没有switch 没有get 和 set  的方法，所以可以直接使用。
     * 但是这里有了get set 所以就把switch 加上了_switch否则则会报错。
     * 
    */
    private _switch:boolean = true;//默认开启音效

    //音乐音效播放器对象池
    private pool:NodePool = new NodePool();
    //对象池子集合
    private effects:Map<string,AudioEffect> = new Map();
    //用过的音效资源
    private res:Map<string,string> = new Map();
    //u音效id
    private _aeId:number = 0;
    // 音效播放的音量
    private _volume:number = 1;

    //#region get set 方法
    public get switch():boolean{
        return this._switch;
    }
    public set switch(value:boolean){
        this._switch = value;
        //这里为什么要停止呢？？
        if (value) {
            this.stop();
        }
    }
    //音量
    public get volume():number{
        return this._volume;
    }

    public set volume(value:number){
        this._volume = value;
        this.effects.forEach(item =>{
            item.volume = value;
        })
    }

    //#endregion

    public async load(url:string | AudioClip,bundleName:string = resLoader.defaultBundleName,onPlayCompleted?:Function):Promise<number>{
        return new Promise(async (resolve,reject)=>{
            if (!this.switch) {
                return reject(-1)
            }
            //获取编号 
            let aeid = this.getAeId();
            let key:string;
            if (url instanceof AudioClip) {
                key  = url.uuid;
            }else{
               key = `${bundleName}_${url}`;
            }

            key += `_${aeid}`;
            let clip:AudioClip;
            if(url instanceof AudioClip){
                clip = url;
            }else{
                clip  = resLoader.get(url,AudioClip,bundleName)!; //排除null
                if (!clip) {
                    this.res.set(bundleName,url);
                    clip = await resLoader.loadAsync(bundleName,url,AudioClip);
                }
            }

            let ae:AudioEffect;
            let node:Node = null!;
            //如果池子中有数据
            if (this.pool.size() > 0) {
                node = this.pool.get()!;
                ae = node.getComponent(AudioEffect)!;
            }else{
                node = new Node("AudioEffect");
                node.parent = hiyooo.audio.node;
                ae = node.addComponent(AudioEffect)!;
            }

            ae.onCompleted = ()=>{
                //播放完成，回收对象
                this.put(aeid,url,bundleName);
                onPlayCompleted && onPlayCompleted();

            }
            this.effects.set(key,ae);
            ae.volume = this.volume;
            ae.clip = clip;
            ae.play();

            resolve(aeid)
        })
    }

    //获取音效ID,如果大于30000则从1开始
    private getAeId():number{
        if (this._aeId>=AE_ID_MAX) {
            this._aeId = 1;
        }
        this._aeId++;
        return this._aeId
    }

    //播放所有音效
    public play():void{
        //如果没有开启音效则不播放
        if (!this.switch) {
            return;
        }
        this.effects.forEach(item =>{
            item.play();
        })

    }

    public pause():void{
        //如果没有开启音效则不暂停
        if (!this.switch) {
            return;
        }
        this.effects.forEach(item=>{
            item.pause();
        })
    }
    //停止所有音效
    public stop():void{
        this.effects.forEach(item =>{
            item.stop();
        })
    }

    //回收对象
    public put(aeid:number,url:string | AudioClip,bundleName:string = resLoader.defaultBundleName){
        let key:string; 
        if (url instanceof AudioClip) {
            key  = url.uuid;
        }else{
            key = `${bundleName}_${url}`
        }
        key += `_${aeid}`;
        let ae  = this.effects.get(key);  
        if (ae && ae.clip) {
            this.effects.delete(key);
            ae.stop();
            this.pool.put(ae.node);
        }
    }

    public release(){
        this.effects.forEach(item=>{
            item.node.destroy();
        })
        //清除所有数据
        this.effects.clear();

        this.res.forEach((url:string,bundleName:string)=>{
            resLoader.release(bundleName,url)
        });
        //清除资源
        this.pool.clear();
    }

}